﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OhioState.Graphics.Proxy;
using OhioState.AssetManaged;

namespace OhioState.Controls
{
    public partial class VectorFieldHistogramForm : Form
    {
        public VectorFieldHistogramForm()
        {
            InitializeComponent();

            cancelButton.DialogResult = DialogResult.Cancel;

            assetManagerDropDownControl1.Init(typeof(VectorField));

            generateButton.Click += new EventHandler(generateButtonClickHandler);
            this.Resize += new EventHandler(resizeHandler);
            this.pictureBox.Click += new EventHandler(pictureBoxMouseClickHandler);
            this.cancelButton.Click += new EventHandler(cancelButtonClickHandler);
        }

        void cancelButtonClickHandler(object sender, EventArgs e)
        {
            this.Close();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            oldWidth = this.Width;
            oldHeight = this.Height;
        }

        private void pictureBoxMouseClickHandler(object sender, EventArgs e)
        {
            MouseEventArgs me = (MouseEventArgs)e;
            float x = me.X / (float)pictureBox.Width;
            float y = me.Y / (float)pictureBox.Height;

            //figure out corresponding velocities
            //from [0, 1] to [-1, 1]
            float vx = x * 2.0f - 1.0f;
            float vy = y * 2.0f - 1.0f;
            vy *= -1;//flip back
            //Console.WriteLine("vx: " + vx + "; vy: " + vy);
            //set up uniform variable for FlowVis shader
            ShaderProgram shader = OhioState.AssetManaged.AssetManager.Instance.Find(typeof(ShaderProgram), "Flow Vis 2D") as ShaderProgram;
            if (shader == null) return;

            //pass vx and vy into the shader
            List<OhioState.AssetManaged.IAssetManaged> list = OhioState.AssetManaged.AssetManager.Instance.FindAll(typeof(MaterialProxy));
            foreach (MaterialProxy materialProxy in list)
            {
                if (materialProxy.Shader == shader)
                {
                    Dictionary<string, UniformVariableValues> uv = materialProxy.UniformVariableValues;
                    foreach (KeyValuePair<String, UniformVariableValues> kvp in uv)
                    {
                        UniformVariableValues val = kvp.Value;
                        if (kvp.Key.Equals("vx"))
                        {
                            val[0].Float = new SharedFloat((float)vx);
                        }
                        else if (kvp.Key.Equals("vx"))
                        {
                            val[0].Float = new SharedFloat((float)vy);
                        }
                    }
                }
            }
        }

        private int oldWidth = -1;
        private int oldHeight = -1;
        private void resizeHandler(object sender, EventArgs e)
        {
            if (oldWidth == -1) oldWidth = this.Width;
            if (oldHeight == -1) oldHeight = this.Height;

            int deltaX = this.Width - oldWidth;
            int deltaY = this.Height - oldHeight;

            pictureBox.Width += deltaX;
            pictureBox.Height += deltaY;
            cancelButton.Location = new System.Drawing.Point(cancelButton.Location.X + deltaX, cancelButton.Location.Y + deltaY);
            generateButton.Location = new System.Drawing.Point(generateButton.Location.X + deltaX, generateButton.Location.Y + deltaY);

            oldWidth = this.Width;
            oldHeight = this.Height;
        }

        private void generateButtonClickHandler(object sender, EventArgs e)
        {
            VectorField vectorField = assetManagerDropDownControl1.GetSelected() as VectorField;
            if (vectorField == null)
                return;
            byte[] data = null;
            vectorField.GetTexture(out data);

            int[,] bins = new int[256, 256];

            //4 components
            for (int i = 0; i < vectorField.Width; i++)
            {
                for (int j = 0; j < vectorField.Height; j++)
                {
                    int index = 4 * i + 4 * vectorField.Width * j;
                    float v_x = data[index]/255.0f;
                    float v_y = data[index + 1]/255.0f;
                    //if v_z == 1.0, inverse direction of v_x
                    //if v_w == 1.0, inverse direction of v_y
                    byte v_z = data[index + 2];
                    byte v_w = data[index + 3];

                    if (v_z == 255) v_x *= -1;
                    if (v_w == 255) v_y *= -1;

                    int binIndexX = (int)(v_x * 127 + 128); //from [-1, 1] to [0, 255]
                    int binIndexY = (int)(v_y * 127 + 128); //from [-1, 1] to [0, 255]

                    bins[binIndexX, binIndexY]++;
                }
            }

            Bitmap bitmap = new Bitmap(256, 256);
            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    int value = bins[i, 255 - j];//flip around x to make it look correct
                    if(value > 255) value = 255;//temp hack!
                    bitmap.SetPixel(i, j, Color.FromArgb(value, value, value));
                }
            }
            pictureBox.Image = bitmap;
        }
    }
}
